var thinkjs = require('thinkjs');

var path = require('path');

var rootPath = path.dirname(__dirname);

const net     = require('net');

const IP      = require('ip');

const EventEmitter = require('events').EventEmitter;

class netServer extends EventEmitter {
    constructor(options){

        super();
        
        this.options = options;

        this._createServer(options);

    }

    _createServer() {

        net.createServer({ pauseOnConnect: true }, (connection)=>{
            this.emit('connection', {
                id: this._getIndex(connection.remoteAddress, this.options.CPU_NUM),
                connection: connection
            });
        }).listen(this.options.port);
    }

    _getIndex(ip, len) {
        return this._hash(IP.toBuffer(ip || '127.0.0.1')) % len;
    }

    _hash(ip) {
        var hash = this.seed;
        for (var i = 0; i < ip.length; i++) {
            var num = ip[i];

            hash += num;
            hash %= 2147483648;
            hash += (hash << 10);
            hash %= 2147483648;
            hash ^= hash >> 6;
        }

        hash += hash << 3;
        hash %= 2147483648;
        hash ^= hash >> 11;
        hash += hash << 15;
        hash %= 2147483648;

        return hash >>> 0;
    }
}

const cluster = require('cluster');

const CPU_NUM = require('os').cpus().length;

if (cluster.isMaster) {

    let master, amqp;

    cluster.on('exit', function (worker, code, signal) {
        console.log('[master] ' + 'exit worker' + worker.id + ' died, try to fork a new worker.');
        process.nextTick(() => cluster.fork());
    });


    var workers = [];
    
    var spawn = function(i) {

        workers[i] = cluster.fork();

        // Worker on error
        workers[i].on('error', function(error) {
            console.log('worker '+ i + ' error: ', error);
        });

        return workers[i];
    };

    // Spawn workers.
    for (var i = 0; i < CPU_NUM; i++) {
        spawn(i);
    }

    // function eachWorker(callback) {
    //     for (var id in cluster.workers) {
    //         callback(cluster.workers[id]);
    //     }
    // }
    function eachWorker(callback) {
        workers.forEach( function(worker) {
            // statements
            callback(worker);
        });
    }

    new netServer({
        'CPU_NUM': CPU_NUM,
        port     : 8444
    }).on('connection', (msg)=>{
        try {
            workers[msg.id].send('papaya-session:connection', msg.connection);
        } catch(e) {
            if(!workers[msg.id].process.connected || workers[msg.id].process.killed){
                spawn(msg.id);
            }
        }
    })

} else if (cluster.isWorker) {

    var instance = new thinkjs({
      APP_PATH: rootPath + path.sep + 'app',
      RUNTIME_PATH: rootPath + path.sep + 'runtime',
      ROOT_PATH: rootPath,
      RESOURCE_PATH: __dirname,
      env: 'development'
    });

    // Build code from src to app directory.
    instance.compile({
      log: true
    });

    instance.run();
}